package tjs.study.antlr.splunkToMysql.v2;

import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import tjs.study.antlr.splunkToMysql.v2.g4.*;

import java.util.List;

public class SplunkToMySQLConverter extends SplunkToMysqlBaseVisitor<String> {
    String mainAlias = "mainAlias";
    static String SUB_SEATCH = "SUB_SEATCH";

    @Override
    public String visitQuery(SplunkToMysqlParser.QueryContext ctx) {
        String indexName = ctx.indexTable().indexName().getText();
        mainAlias = ctx.indexTable().indexAlias() != null ? ctx.indexTable().indexAlias().getText() : mainAlias;

        MyStringBuilder res = new MyStringBuilder()
                .append("SELECT ")
                .appendNext(visitAllTableFields(ctx.allTableFields()))
                .append(" FROM ").append(indexName).append(" AS ").appendNext(mainAlias)
                .appendNext(visitLookup(ctx.lookup()))
                .appendNext(visitSearch(ctx.search()));

        String statsCount = visitStatsCount(ctx.statsCount());
        if (!StringUtils.isEmpty(statsCount)) {
            res = new MyStringBuilder(statsCount.replace(SUB_SEATCH,
                    // 美化输出
                    "    " + res.toString().replaceAll("\n", "\n    ")));
        }
        return res.toString();
    }


    public String visitAllTableFields(List<SplunkToMysqlParser.AllTableFieldsContext> ctxs) {
        MyStringBuilder res = new MyStringBuilder();
        for (SplunkToMysqlParser.AllTableFieldsContext ctx : ctxs) {
            res.appendNext(visitAllTableFields(ctx), ",");
        }
        String resStr = res.subStringLast(",").toString();
        return StringUtils.isEmpty(resStr) ? "*" : resStr;
    }

    @Override
    public String visitAllTableFields(SplunkToMysqlParser.AllTableFieldsContext ctx) {
        if (ctx == null) {
            return "";
        }
        MyStringBuilder res = new MyStringBuilder();
        res.append(visitTableFields(ctx.tableFields()));
        res.append(visitFillnull(ctx.fillnull()));
        res.append(visitRename(ctx.rename()));
        return res.toString();
    }

    @Override
    public String visitTableFields(SplunkToMysqlParser.TableFieldsContext ctx) {
        if (ctx == null || ctx.fields() == null || ctx.fields().isEmpty()) {
            return "";
        }
        List<SplunkToMysqlParser.FieldNameContext> fields = ctx.fields().fieldName();
        StringBuilder mysqlQuery = new StringBuilder();
        for (int i = 0; i < fields.size(); i++) {
            mysqlQuery.append(fields.get(i).getText());
            if (i < fields.size() - 1) {
                mysqlQuery.append(", ");
            }
        }
        return mysqlQuery.toString();
    }


    /**
     * @return ifNull(whitelistStatus, ' SRC_NOT_RIS ') AS whitelistStatus
     * @source fillnull value="SRC_NOT_RIS" whitelistStatus
     */
    @Override
    public String visitFillnull(SplunkToMysqlParser.FillnullContext ctx) {
        if (ctx == null || ctx.oneFieldName() == null || ctx.oneFieldName().isEmpty()) {
            return "";
        }
        return " IFNULL(" + ctx.oneFieldName().getText() + "," +
                " '" + MyStringBuilder.getVal(ctx.oneFieldValue().getText()) + "')" +
                " AS " + ctx.oneFieldName().getText();
    }

    @Override
    public String visitRename(SplunkToMysqlParser.RenameContext ctx) {
        if (ctx == null || ctx.oneFieldName() == null || ctx.oneFieldName().isEmpty()) {
            return "";
        }
        return " " + ctx.oneFieldName().getText() + " AS " + ctx.fieldAliasName().getText();
    }

    /**
     * @source lookup ris_src_whitelist2023 ip AS src_ip
     * @targe join ris_src_whitelist2023 ON ris_src_whitelist2023.ip = mainT.src_ip
     */
    @Override
    public String visitLookup(SplunkToMysqlParser.LookupContext ctx) {
        if (ctx == null || ctx.fieldNameAs() == null || ctx.fieldNameAs().isEmpty()) {
            return "";
        }
        String joinKey = ctx.fieldNameAs().getText();
        String targetTableName = ctx.indexName().getText();//ip AS src_ip
        String joinTableBody = targetTableName;
        if (ctx.fields() != null && !CollectionUtils.isEmpty(ctx.fields().fieldName())) {
            // 只查出必要字段
            MyStringBuilder need = new MyStringBuilder()
                    .appendNext("(")
                    .append("   SELECT ");

            need.append(ctx.fieldNameAs().fieldAliasName().getText()).append(", ");
            for (SplunkToMysqlParser.FieldNameContext fieldNameContext : ctx.fields().fieldName()) {
                need.append(fieldNameContext.getText().replaceFirst(",", "")).append(", ");
            }
            need.subStringLast(", ");

            need.append("\n    FROM ").append(targetTableName)
                    //todo-tjs 自动筛选时间
                    .append("\n ) ").append(targetTableName);
            joinTableBody = need.toString();
        }
        return " JOIN " + joinTableBody + " ON " + targetTableName + "." + joinKey.replace(" AS ", " = " + mainAlias + ".");
    }

    /**
     * @source search src_ip=10.10.* OR src_ip=10.172.* OR src_ip=10.173.*
     * @targe where mainAlias.src_ip like '%10.10%' OR mainAlias.src_ip like '%10.172%'
     */
    @Override
    public String visitSearch(SplunkToMysqlParser.SearchContext ctx) {
        if (ctx == null || ctx.condition() == null || ctx.condition().isEmpty()) {
            return "";
        }
        StringBuilder res = new StringBuilder("WHERE ");
        appendWhere(res, ctx.condition());
        for (SplunkToMysqlParser.ConditionMoreContext logicalOperatorContext : ctx.conditionMore()) {
            res.append(" ").append(logicalOperatorContext.OPERATION().getText()).append(" ");
            appendWhere(res, logicalOperatorContext.condition());
        }
        return res.toString();
    }


    /**
     * @source stats count by src_ip
     * @targe SELECT %s, COUNT(*) AS count FROM \n(SUB_SEATCH)\n group by %s
     */
    @Override
    public String visitStatsCount(SplunkToMysqlParser.StatsCountContext ctx) {
        if (ctx == null || ctx.oneFieldName() == null || ctx.oneFieldName().isEmpty()) {
            return "";
        }
        String fieldName = ctx.oneFieldName().getText();
        return String.format("SELECT %s, COUNT(*) AS count \nFROM (\nSUB_SEATCH\n) GROUP BY %s",
                fieldName, fieldName);
    }

    private static void appendWhere(StringBuilder res, SplunkToMysqlParser.ConditionContext conditionContext) {
        String filedName = conditionContext.oneFieldName().getText();
        String filedVale = conditionContext.oneFieldValue().getText();
        if (filedVale.contains(".*")) {
            res.append(filedName).append(String.format(".like('%s')", "%" + MyStringBuilder.getVal(filedVale.replace(".*", "")) + "%"));
        } else {
            res.append(conditionContext.getText());
        }
    }


    public static class MyStringBuilder {
        private StringBuilder res;

        public MyStringBuilder() {
            this.res = new StringBuilder();
        }

        public MyStringBuilder(String res) {
            this.res = new StringBuilder(res);
        }

        public MyStringBuilder subStringLast(String split) {
            if (res.length() == 0 || res.lastIndexOf(split) != res.length() - split.length()) {
                return this;
            }
            // todo-tjs 判空
            res = new StringBuilder(res.substring(0, res.length() - split.length()));
            return this;
        }

        public MyStringBuilder append(String row) {
            res.append(row);
            return this;
        }

        public MyStringBuilder appendNext(String row) {
            if (StringUtils.isEmpty(row)) {
                return this;
            }
            res.append(row).append("\n");
            return this;
        }

        public MyStringBuilder appendNext(String row, String split) {
            if (StringUtils.isEmpty(row)) {
                return this;
            }
            if (res.length() > 0 && res.lastIndexOf(split) != res.length() - split.length()) {
                res.append(split);
            }
            res.append(row).append(split);
            return this;
        }

        public MyStringBuilder appendNextOnly(String row, String split) {
            if (StringUtils.isEmpty(row)) {
                return this;
            }
            if (res.length() > 0 && res.lastIndexOf(split) != res.length() - split.length()) {
                res.append(split);
            }
            res.append(row);
            return this;
        }

        public static String getVal(String item) {
            if (item == null) {
                return item;
            }
            item = item.startsWith("'") ? item.substring(1, item.length()) : item;
            item = item.startsWith("\"") ? item.substring(1, item.length()) : item;
            item = item.endsWith("'") ? item.substring(0, item.length() - 1) : item;
            item = item.endsWith("\"") ? item.substring(0, item.length() - 1) : item;
            return item;
        }

        @Override
        public String toString() {
            return subStringLast("\n").res.toString();
        }
    }
}